#include "Common.h"

std::string CONF_PATH = "";

volatile bool SAFE_STOP_FLAG = false;

void _WriteLog(int LEVEL, char *file, int line, char *fmt, ...)
{
    static pthread_mutex_t  mutex=PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_lock(&mutex);

    time_t t = time(0);
    char tmp[20];
    strftime(tmp, sizeof(tmp), "%Y-%m-%d %X",localtime(&t) );
    va_list ap;
    va_start(ap, fmt );
    if(LEVEL == 0)
    {
        printf("[DEBUG:%s %s:%d] ", tmp, file, line);
    }
    else if(LEVEL == 1)
    {
        printf("[NOTICE:%s %s:%d] ", tmp, file, line);
    }
    else if(LEVEL == 2)
    {
        printf("[WARNING:%s %s:%d] ", tmp, file, line);
    }
    else
    {
        printf("[FATAL:%s %s:%d] ", tmp, file, line);
    }
    vprintf(fmt, ap);
    printf("\n");
    va_end(ap);

    pthread_mutex_unlock(&mutex);
}

int32 SocketRead(int32 fd, char *buf, int32 nbytes, int32 timeOut)
{
    if(fd < 0 || buf == NULL)
    {
        return -1;
    }

    int32 nleft = nbytes;
    int32 nread = 0;
    Timer timer;
    timer.Start();
    while(nleft > 0)
    {
        if(timer.Diff() >= timeOut)
        {
            return -1;
        }
        nread = 0;
        if((nread = recv(fd, buf, nleft, MSG_DONTWAIT)) < 0)
        {
            if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
            {
                usleep(2);
                continue;
            }
            return -2;
        }
        if(nread == 0)
        {
            break;
        }
        nleft -= nread;
        buf += nread;
    }
    return nbytes - nleft;
}

int32 SocketWrite(int32 fd, const char *buf, int32 nbytes, int32 timeOut)
{
    if(fd < 0 || buf == NULL)
    {
        return -1;
    }

    int32 nleft = nbytes;
    int32 nwrite = 0;
    Timer timer;
    timer.Start();
    while(nleft > 0)
    {
        if(timer.Diff() >= timeOut)
        {
            return -1;
        }
        nwrite = 0;
        if((nwrite = write(fd, buf, nleft)) < 0)
        {
            if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
            {
                usleep(2);
                continue;
            }
            return -2;
        }
        nleft -= nwrite;
        buf += nwrite;
    }

    return nbytes;
}

std::string GetIP(struct sockaddr_in* addr)
{
    const int IP_STR_LEN = 32;
    char ipStr[IP_STR_LEN];
    memset(ipStr, 0, IP_STR_LEN);

    if(inet_ntop(AF_INET, (void*)(&(addr->sin_addr)), ipStr, IP_STR_LEN) != NULL)
    {
        return std::string(ipStr);
    }
    else
    {
        return std::string("");
    }
}

int32 GetPort(struct sockaddr_in* addr)
{
    return ntohs(addr->sin_port);
}

std::string ltrim(std::string str, std::string rmv)
{
    uint32 idx = 0;
    for (idx = 0; idx < str.size(); idx++)
    {
        if (rmv.find(std::string(&(str[idx]), 1)) == std::string::npos)
        {
            break;
        }
    }

    return idx == str.size() ? "" : str.substr(idx, str.size() - idx);
}

std::string rtrim(std::string str, std::string rmv)
{
    if(str.size() == 0)
    {
        return "";
    }

    int32 idx = str.size() - 1;
    for(idx = str.size() - 1; idx >= 0; idx--)
    {
        if (rmv.find(std::string(&(str[idx]), 1)) == std::string::npos)
        {
            break;
        }
    }

    return idx == -1 ? "" : str.substr(0, idx + 1);
}

std::string trim(std::string str, std::string rmv)
{
    return rtrim(ltrim(str, rmv), rmv);
}

int32 Split(std::string str, std::string delim, std::vector<std::string>& parts)
{
    if(delim.length() == 0)
    {
        return -1;
    }

    size_t idx;
    while((idx = str.find(delim)) != std::string::npos)
    {
        parts.push_back(str.substr(0, idx));
        str = str.substr(idx + delim.length());
    }

    if(str.size() > 0)
    {
        parts.push_back(str);
    }

    return 0;
}

double TimeDiff(timeval_t s, timeval_t e)
{
    return (e.tv_sec - s.tv_sec)*1000 + (double)(e.tv_usec - s.tv_usec)/1000.0;
}

timeval_t GetNowTimeVal()
{
    timeval_t t;
    gettimeofday(&t, NULL);
    return t;
}

void Timer::Start()
{
    gettimeofday(&s, NULL);
}

double Timer::Diff()
{
    gettimeofday(&e, NULL);
    return TimeDiff(s, e);
}
